package com.lechi.web.util;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 高效缓存，针对没有并发写的操作
 */
public class LeChiCacheUtil {
    private final static ScheduledExecutorService exector = Executors.newSingleThreadScheduledExecutor();

    private final static Map<String, FutureObj> map = new HashMap<>();

    /**
     * Put.
     *
     * @param key   the key
     * @param value the value
     */
    public static void put(String key, Object value) {
        LeChiCacheUtil.put(key, value, 0);
    }

    /**
     * Remove object.
     *
     * @param key the key
     * @return the object
     */
    public static Object remove(String key) {
        FutureObj val = map.remove(key);
        if (val == null) {
            return null;
        }
        Future future = val.getFuture();
        if (future != null) {
            future.cancel(true);
        }
        return val.getValue();
    }

    /**
     * Size int.
     *
     * @return the int
     */
    public static int size() {
        return map.size();
    }

    /**
     * Put.
     *
     * @param key        the key
     * @param value      the value
     * @param expireTime the expire time
     */
    public static void put(String key, Object value, long expireTime) {
        LeChiCacheUtil.remove(key);
        if (expireTime > 0) {
            Future future = exector.schedule(() -> {
                map.remove(key);
            }, expireTime, TimeUnit.SECONDS);
            map.put(key, new FutureObj(value, future));
        } else {
            map.put(key, new FutureObj(value, null));
        }
    }

    /**
     * Get object.
     *
     * @param key the key
     * @return the object
     */
    public static Object get(String key) {
        FutureObj futureObj = map.get(key);
        return futureObj == null ? null : futureObj.getValue();
    }

    /**
     * Get t.
     *
     * @param <T> the type parameter
     * @param key the key
     * @param cla the cla
     * @return the t
     */
    public static <T> T get(String key, Class<T> cla) {
        return cla.cast(LeChiCacheUtil.get(key));
    }

    private static class FutureObj {
        private final Object value;

        private final Future future;

        /**
         * Instantiates a new Future obj.
         *
         * @param value  the value
         * @param future the future
         */
        public FutureObj(Object value, Future future) {
            this.value = value;
            this.future = future;
        }

        /**
         * Gets value.
         *
         * @return the value
         */
        public Object getValue() {
            return value;
        }

        /**
         * Gets future.
         *
         * @return the future
         */
        public Future getFuture() {
            return future;
        }
    }
}
